package com.tbit.uqbike.webmanager.business.operationreport.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.excel.util.CollectionUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.common.entity.vo.*;
import com.tbit.uqbike.constant.enums.AccountDayStatEnum;
import com.tbit.uqbike.object.pojo.Account;
import com.tbit.uqbike.object.pojo.dto.OrderAnalysisForOpRepDTO;
import com.tbit.uqbike.object.pojo.dto.OrderAnalysisForOpRepListDTO;
import com.tbit.uqbike.object.pojo.dto.OrderAnalysisQueryDTO;
import com.tbit.uqbike.object.pojo.vo.OperationReportExcelVo;
import com.tbit.uqbike.object.view.JsonResult;
import com.tbit.uqbike.webmanager.business.operationreport.service.OperationReportNewService;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import com.tbit.uqbike.webmanager.dao.stat.AccountDayStatDao;
import com.tbit.uqbike.webmanager.dao.stat.OrderAnalysisDao;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.utils.DateTimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 运营报表-新-服务层接口实现类
 *
 * @author: qiu.longjie
 * @create: 2025-05-08
 */
@Service
public class OperationReportServiceNewImpl implements OperationReportNewService {

    @Autowired
    private AccountDayStatDao accountDayStatDao;
    @Autowired
    private OrderAnalysisDao orderAnalysisDao;
    @Autowired
    private AccountDao accountDao;

    /**
     * 获取数据-概况
     *
     * @param vo
     * @return
     */
    @Override
    public OperationReportRespBoxVo getDataBox(OperationReportReqVo vo) {
        // 获取预统计所需的相关dataType数据
        List<Integer> accountIdList = vo.getAccountIdList();
        AccountDayStatEnum[] operationReportEnums = AccountDayStatEnum.getOperationReportEnums();
        List<Integer> operationalDataType = Arrays.stream(operationReportEnums).map(AccountDayStatEnum::getDataType).collect(Collectors.toList());
        // 数据的日期范围，默认是最近7天数据。
        Integer beginDataDate = vo.getDaysAgo(6);
        Integer endDataDate = vo.getDataDate();
        Map<Integer, Map<String, Object>> dataMap = accountDayStatDao.operationalReportSumDay(beginDataDate, endDataDate, accountIdList, null, operationalDataType);
        if (CollectionUtils.isEmpty(dataMap)) {
            return OperationReportRespBoxVo.empty();
        }
        // 从orderanalysisStat统计表中获取运营报表列表相关的字段数据
        OrderAnalysisQueryDTO orderAnalysisQueryDTO = new OrderAnalysisQueryDTO();
        orderAnalysisQueryDTO.setAccountIds(accountIdList);
        orderAnalysisQueryDTO.setDateTimeStart(String.valueOf(beginDataDate));
        orderAnalysisQueryDTO.setDateTimeEnd(String.valueOf(endDataDate));
        List<OrderAnalysisForOpRepDTO> orderAnalysisList = orderAnalysisDao.getOrderAnalysisForOperationReportBetween(orderAnalysisQueryDTO);
        Map<String, OrderAnalysisForOpRepDTO> orderAnalysisMap = orderAnalysisList.stream()
                .collect(
                        Collectors.toMap(
                                OrderAnalysisForOpRepDTO::getDateTime,
                                Function.identity(),
                                (oldValue, newValue) -> oldValue
                        )
                );
        // 获取开始日期到结束日期之间的所有日期
        List<Integer> dateList = DateTimeUtil.getDateRange(beginDataDate, endDataDate);
        // 拼装这几天数据到集合
        List<OperationReportRespVo> operationReportRespVos = new ArrayList<>(dateList.size());
        dateList.forEach(date -> {
            OperationReportRespVo reportRespVo = new OperationReportRespVo();
            Map<String, Object> record = dataMap.get(date);
            // 填充运营报表字段数据
            reportRespVo = convertToOperationReportRespVo(record, reportRespVo);
            // 填充总扫码次数、总开锁次数、开锁成功次数、有效骑行次数、骑行失败次数。
            setAboutUserOpMachineField(orderAnalysisMap.get(date.toString()), reportRespVo);
            operationReportRespVos.add(reportRespVo);
        });

        return new OperationReportRespBoxVo().convert(operationReportRespVos);
    }

    /**
     * 获取数据
     *
     * @param vo
     * @return
     */
    @Override
    public OperationReportRespVo getData(OperationReportReqVo vo) {
        // 获取预统计所需的相关dataType数据
        List<Integer> accountIdList = vo.getAccountIdList();
        AccountDayStatEnum[] operationReportEnums = AccountDayStatEnum.getOperationReportEnums();
        List<Integer> operationalDataType = Arrays.stream(operationReportEnums).map(AccountDayStatEnum::getDataType).collect(Collectors.toList());
        Map<Integer, Map<String, Object>> dataMap = accountDayStatDao.operationalReportSumDay(vo.getDataDate(), vo.getDataDate(), accountIdList, null, operationalDataType);
        if (CollectionUtils.isEmpty(dataMap)) {
            return OperationReportRespVo.empty();
        }
        OperationReportRespVo reportRespVo = new OperationReportRespVo();
        Map<String, Object> record = dataMap.get(vo.getDataDate());
        // 填充运营报表字段数据
        reportRespVo = convertToOperationReportRespVo(record, reportRespVo);
        // 从orderanalysisStat统计表中获取运营报表列表相关的字段数据
        OrderAnalysisQueryDTO orderAnalysisQueryDTO = new OrderAnalysisQueryDTO();
        orderAnalysisQueryDTO.setAccountIds(accountIdList);
        orderAnalysisQueryDTO.setDateTime(String.valueOf(vo.getDataDate()));
        OrderAnalysisForOpRepDTO orderAnalysisForOpRepDTO = orderAnalysisDao.getOrderAnalysisForOperationReport(orderAnalysisQueryDTO);
        // 填充总扫码次数、总开锁次数、开锁成功次数、有效骑行次数、骑行失败次数。
        setAboutUserOpMachineField(orderAnalysisForOpRepDTO, reportRespVo);
        return reportRespVo;
    }

    /**
     * 列表数据
     *
     * @param vo
     * @return
     */
    @Override
    public PageResult<OperationReportListRespVo> listData(OperationReportListReqVo vo) {
        // 获取预统计所需的相关dataType数据
        List<Integer> accountIdList = vo.getAccountIdList();
        PageInfo<Map<String, Object>> pageInfo = PageHelper.startPage(vo.getPageNO(), vo.getPageSize())
                .doSelectPageInfo(
                        () -> operationalReportMultiDay(vo.getBeginDataDate(), vo.getEndDataDate(), accountIdList)
                );
        if (CollectionUtils.isEmpty(pageInfo.getList())) {
            return new PageResult<OperationReportListRespVo>(vo.getPageNO(), vo.getPageSize(), 0L, 0, Collections.emptyList());
        }
        // 从orderanalysisStat统计表中获取运营报表列表相关的字段数据，格式<accountId_dateTime,数据>
        Map<String, OrderAnalysisForOpRepListDTO> dataFromOrderAnalysisMap = getDataFromOrderAnalysis(vo, accountIdList);
        // 获取区域名称<accountId,accountName>
        Map<Integer, String> accountName = getAccountName(accountIdList);
        List<OperationReportListRespVo> respVoList = pageInfo.getList().stream()
                .map(this::convertToOperationReportListRespVo)
                .peek(v -> setOthersData(v, dataFromOrderAnalysisMap, accountName))
                .collect(Collectors.toList());
        // 组装分页数据
        return new PageResult<>(vo.getPageNO(), vo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages(), respVoList);
    }

    @Override
    public Result<Object> exportData(OperationReportListReqBaseVo vo) {
        // 获取预统计所需的相关dataType数据
        List<Integer> accountIdList = vo.getAccountIdList();
        Map<String, Map<String, Object>> dataMap = operationalReportMultiDay(vo.getBeginDataDate(), vo.getEndDataDate(), accountIdList);
        if (CollectionUtils.isEmpty(dataMap)) {
            return Result.success();
        }
        // 从orderanalysisStat统计表中获取运营报表列表相关的字段数据，格式<accountId_dateTime,数据>
        Map<String, OrderAnalysisForOpRepListDTO> dataFromOrderAnalysisMap = getDataFromOrderAnalysis(vo, accountIdList);
        // 获取区域名称<accountId,accountName>
        Map<Integer, String> accountName = getAccountName(accountIdList);
        // 组装数据到OperationReportListRespVo对象
        List<OperationReportListRespVo> respVoList = dataMap.values().stream()
                .map(this::convertToOperationReportListRespVo)
                .peek(v -> setOthersData(v, dataFromOrderAnalysisMap, accountName))
                .collect(Collectors.toList());
        // 把respVoList转换为Excel导出数据
        List<OperationReportExcelVo> list = respVoList.stream().map(this::convertToOperationReportExcelVo).collect(Collectors.toList());
        ExcelUtil<OperationReportExcelVo> excelUtil = new ExcelUtil<>(OperationReportExcelVo.class);
        String fileName = String.format("%s~%s_运营日报", vo.getBeginDataDate(), vo.getEndDataDate());
        JsonResult result = excelUtil.exportExcel(list, fileName);
        return Result.success(result.getData());
    }

    private OperationReportExcelVo convertToOperationReportExcelVo(OperationReportListRespVo reportListRespVo) {
        return BeanUtil.copyProperties(reportListRespVo, OperationReportExcelVo.class);
    }

    // 运营报表-列表数据，相关所需的dataType数据
    private Map<String, Map<String, Object>> operationalReportMultiDay(Integer beginDataDate, Integer endDataDate, List<Integer> accountIdList) {
        AccountDayStatEnum[] operationReportEnums = AccountDayStatEnum.getOperationReportEnums();
        List<Integer> operationalDataType = Arrays.stream(operationReportEnums).map(AccountDayStatEnum::getDataType).collect(Collectors.toList());
        return accountDayStatDao.operationalReportMultiDay(beginDataDate, endDataDate, accountIdList, null, operationalDataType);
    }

    private Map<String, OrderAnalysisForOpRepListDTO> getDataFromOrderAnalysis(OperationReportListReqBaseVo vo, List<Integer> accountIdList) {
        OrderAnalysisQueryDTO orderAnalysisQueryDTO = new OrderAnalysisQueryDTO();
        orderAnalysisQueryDTO.setAccountIds(accountIdList);
        orderAnalysisQueryDTO.setDateTimeStart(String.valueOf(vo.getBeginDataDate()));
        orderAnalysisQueryDTO.setDateTimeEnd(String.valueOf(vo.getEndDataDate()));
        List<OrderAnalysisForOpRepListDTO> orderAnalysisForOperationReportList = orderAnalysisDao.getOrderAnalysisForOperationReportList(orderAnalysisQueryDTO);
        if (!CollectionUtils.isEmpty(orderAnalysisForOperationReportList)) {
            // <accountId_dateTime,数据>
            return orderAnalysisForOperationReportList.stream()
                    .collect(
                            Collectors.toMap(
                                    OrderAnalysisForOpRepListDTO::getFlag,
                                    Function.identity(),
                                    (key1, key2) -> key2)
                    );
        }
        return Collections.emptyMap();
    }

    private Map<Integer, String> getAccountName(List<Integer> accountIdList) {
        List<Account> accountNameList = accountDao.getAccountNameByIdList(accountIdList);
        if (!CollectionUtils.isEmpty(accountNameList)) {
            return accountNameList.stream().collect(
                    Collectors.toMap(Account::getAccountId, Account::getName, (key1, key2) -> key2)
            );
        }
        return Collections.emptyMap();
    }

    // 设置其他字段数据
    private void setOthersData(OperationReportListRespVo listRespVo, Map<String, OrderAnalysisForOpRepListDTO> dataFromOrderAnalysisMap, Map<Integer, String> accountName) {
        // 设置 总扫码次数、总开锁次数、开锁成功次数、有效骑行次数、骑行失败次数。
        setAboutUserOpMachineField(dataFromOrderAnalysisMap.get(listRespVo.getFlag()), listRespVo);
        // 设置 区域名称
        listRespVo.setAccountName(accountName.getOrDefault(listRespVo.getAccountId(), "未知区域"));
    }

    // 设置 总扫码次数、总开锁次数、开锁成功次数、有效骑行次数、骑行失败次数。
    private void setAboutUserOpMachineField(OrderAnalysisForOpRepDTO orderAnalysisForOpRepDTO, OperationReportRespVo reportRespVo) {
        if (orderAnalysisForOpRepDTO != null) {
            reportRespVo.setAboutUserOpMachineField(
                    orderAnalysisForOpRepDTO.getScanCodeCount(),
                    orderAnalysisForOpRepDTO.getUnlockCount(),
                    orderAnalysisForOpRepDTO.getSuccessUnlockCount(),
                    orderAnalysisForOpRepDTO.getValidOrderCount()
            );
        } else {
            reportRespVo.setAboutUserOpMachineField(0, 0, 0, 0);
        }
    }

    /**
     * 设置运营报表字段数据
     * <br/>
     * 需要从accountdaystat获取的数据类型
     * <br/>
     * 总车辆数： (accountdaystat  dataType=40  车辆总数)
     * 投放车辆数： (accountdaystat  dataType=41  已投放车辆数)
     * 可运营车辆数：(accountdaystat  dataType=59  可运营车辆数 确定)
     * 不可运营车辆数： 已投放车辆数-可运营车辆数
     * 故障车辆数：(accountdaystat  dataType=107  故障车辆数)
     * 订单车辆数 dataType=134
     * 有效订单车辆数 dataType=135
     * 车辆投放率：投放车辆数/总车辆数
     * 车辆可用率：可运营车辆数/投放车辆数
     * 车辆故障率：故障车辆数/投放车辆数
     * 车辆骑行率：产生订单车辆数/投放车辆数
     * 车辆有效骑行率：有效订单车辆数/投放车辆数
     * 3天无订单车辆数：dataType=136 3天有订单车辆数 sumTotal - cntTotal
     * 7天无订单车辆数：dataType=137 7天有订单车辆数 sumTotal - cntTotal
     * 15天无订单车辆数：dataType=138 15天有订单车辆数 sumTotal - cntTotal
     * 3天无订单车辆率：3天无订单车辆数/3天加入的车辆数
     * 7天无订单车辆率：7天无订单车辆数/7天加入的车辆数
     * 15天无订单车辆率；15天无订单车辆数/15天加入的车辆数
     * 应收订单金额 – dataType=139 sumTatol
     * 应收订单数 – dataType=139 cntTatol
     * 实收订单金额 dataType=1 sumTatol + dataType=3 sumTatol
     * 实收订单数  dataType=1 cntTatol
     * 退款金额：dataType=58 sumTatol
     * 退款订单数：dataType=58 cntTatol
     * 骑行卡收入金额:  dataType=5 sumTatol
     * 骑行卡收入订单数： dataType=5 cntTatol
     * 期末总预存款金额：  dataType=19 sumTatol
     * 应收车均收益： 应收订单金额/投放车辆数
     * 实收车均收益： 实收订单金额/投放车辆数
     * 应收车均单量： 应收订单数/投放车辆数
     * 实收车均单量： 实收订单数/投放车辆数
     * 应收车均里程：（累计骑行总里程 米转公里：dataType=102）/ 应收订单数
     * 实收车均里程：（累计骑行总里程：dataType=102）/ 实收订单数
     * 应收车均时长：骑行总时长（分钟） dataType=133 秒 / 应收订单数
     * 实收车均时长；骑行总时长（分钟）dataType=133 秒 / 实收订单数
     * 总用户数：(dataType=70  累计用户数)
     * 新增用户数：(dataType=43  新增用户数)
     * 骑行用户数  dataType=123
     * 3天未骑行用户数：累计用户数 - dataType=140 3天有骑行用户数
     * 7天未骑行用户数：累计用户数 - dataType=141 7天有骑行用户数
     * 15天未骑行用户数：累计用户数 - dataType=142 15天有骑行用户数
     * 新用户7日留存率：7dataType=143 7日留存率
     * 总扫码次数：orderanalysisstat . scanCodeCount
     * 总开锁次数：orderanalysisstat . unlockCount
     * 开锁成功次数：orderanalysisstat . successUnlockCount
     * 有效骑行次数：orderanalysisstat . validOrderCount
     * 骑行失败次数：总开锁次数 - 开锁成功次数
     * 丢单次数 dataType=145
     * 总换电次数：(accountdaystat  dataType=67 换电次数)
     * 总挪车次数：(accountdaystat  dataType=68 换电次数)
     * 总调度次数：(accountdaystat  dataType=69 换电次数)
     * 总维修次数：(accountdaystat  dataType=125 维修数)
     * 换电有效率：dataType=144
     * 挪车完成率：(accountdaystat  dataType=66 挪车完成率)
     * 调度有效率：(accountdaystat  dataType=65 调度有效率)
     * 维修完成率；(accountdaystat  dataType=64 维修完成率)
     * 调度后12小时成单率 dataType=146 存储的是4为小数的整数值 除以100转为百分比
     */
    private OperationReportRespVo convertToOperationReportRespVo(Map<String, Object> record, OperationReportRespVo vo) {
        if (record == null) {
            return OperationReportListRespVo.empty();
        }
        vo
                // 总车辆数： (dataType=40  车辆总数)
                .setTotalMachine(getIntegerValue(record, AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES, true))
                // 投放车辆数： (dataType=41  已投放车辆数)
                .setPutInTotalMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_VEHICLES_LAUNCHED, true))
                // 可运营车辆数：(dataType=59  可运营车辆数)
                .setOperationalMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_OPERATIONAL_VEHICLES, true))
                // 不可运营车辆数： 已投放车辆数-可运营车辆数
                .setUnOperationalMachine(vo.getPutInTotalMachine() - vo.getOperationalMachine())
                // 故障车辆数：(dataType=107  故障车辆数)
                .setFaultMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_BROKEN_DOWN_VEHICLES, true))
                // 订单车辆数 dataType=134
                .setOrderMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_ORDER_VEHICLES, true))
                // 有效订单车辆数 dataType=135
                .setValidOrderMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_VALID_ORDER_VEHICLES, true))
                // 车辆投放率：投放车辆数/总车辆数
                .setMachinePutInRate(handleRate(vo.getPutInTotalMachine(), vo.getTotalMachine()))
                // 车辆可用率：可运营车辆数/投放车辆数
                .setMachineAvailableRate(handleRate(vo.getOperationalMachine(), vo.getPutInTotalMachine()))
                // 车辆故障率：故障车辆数/投放车辆数
                .setMachineFaultRate(handleRate(vo.getFaultMachine(), vo.getPutInTotalMachine()))
                // 车辆骑行率：产生订单车辆数/投放车辆数
                .setMachineRidingRate(handleRate(vo.getOrderMachine(), vo.getPutInTotalMachine()))
                // 车辆有效骑行率：有效订单车辆数/投放车辆数
                .setMachineValidRidingRate(handleRate(vo.getValidOrderMachine(), vo.getPutInTotalMachine()))
                // 3天无订单车辆数： dataType=136 3天有订单车辆数 sumTotal - cntTotal
                .setThreeDaysNoOrderMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_3_LAST_DAY_ORDER_VEHICLES, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_3_LAST_DAY_ORDER_VEHICLES, true))
                // 7天无订单车辆数： dataType=137  7天有订单车辆数 sumTotal - cntTotal
                .setSevenDaysNoOrderMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_7_LAST_DAY_ORDER_VEHICLES, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_7_LAST_DAY_ORDER_VEHICLES, true))
                // 15天无订单车辆数：dataType=138  15天有订单车辆数 sumTotal - cntTotal
                .setFifteenDaysNoOrderMachine(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_15_LAST_DAY_ORDER_VEHICLES, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_15_LAST_DAY_ORDER_VEHICLES, true))
                // 3天无订单车辆率：3天无订单车辆数/3天加入的车辆数
                .setThreeDaysNoOrderRate(handleRate(vo.getThreeDaysNoOrderMachine(), getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_3_LAST_DAY_ORDER_VEHICLES, false)))
                // 7天无订单车辆率：7天无订单车辆数/7天加入的车辆数
                .setSevenDaysNoOrderRate(handleRate(vo.getSevenDaysNoOrderMachine(), getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_7_LAST_DAY_ORDER_VEHICLES, false)))
                // 15天无订单车辆率；15天无订单车辆数/15天加入的车辆数
                .setFifteenDaysNoOrderRate(handleRate(vo.getFifteenDaysNoOrderMachine(), getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_15_LAST_DAY_ORDER_VEHICLES, false)))
                // 应收订单金额 – dataType=139 sumTatol
                .setTotalOrderAmount(fenToYuan(getLongValue(record, AccountDayStatEnum.SUM_AND_CNT_OF_SHOULD_ORDER, false)))
                // 应收订单数 – dataType=139 cntTatol
                .setTotalOrderCount(getIntegerValue(record, AccountDayStatEnum.SUM_AND_CNT_OF_SHOULD_ORDER, true))
                // 实收订单金额 dataType=1 sumTatol + dataType=3 sumTatol
                .setTotalReceiptOrderAmount(fenToYuan(getLongValue(record, AccountDayStatEnum.CYCLING_INCOME, false) + getLongValue(record, AccountDayStatEnum.USER_FINE_INCOME, false)))
                // 实收订单数  dataType=1 cntTatol
                .setTotalReceiptOrderCount(getIntegerValue(record, AccountDayStatEnum.CYCLING_INCOME, true))
                // 退款金额：dataType=58 sumTatol
                .setRefundAmount(fenToYuan(getLongValue(record, AccountDayStatEnum.OPERATING_EXPENSES, false)))
                // 退款订单数：dataType=58 cntTatol
                .setRefundOrderCount(getIntegerValue(record, AccountDayStatEnum.OPERATING_EXPENSES, true))
                // 骑行卡收入金额 dataType=5 sumTatol
                .setRidingCardIncomeAmount(fenToYuan(getLongValue(record, AccountDayStatEnum.INCOME_FROM_CYCLING_CARD, false)))
                // 骑行卡收入订单数  dataType=5 cntTatol
                .setRidingCardIncomeOrderCount(getIntegerValue(record, AccountDayStatEnum.INCOME_FROM_CYCLING_CARD, true))
                // 期末总预存款金额 dataType=19 sumTatol
                .setTotalPreDepositAmount(fenToYuan(getLongValue(record, AccountDayStatEnum.OPENING_AND_CLOSING_BALANCE, false)))
                // 应收车均收益 = 应收订单金额/投放车辆数
                .setTotalMachineAgv(handleDiv(vo.getTotalOrderAmount(), Double.valueOf(vo.getPutInTotalMachine())))
                // 实收车均收益 = 实收订单金额/投放车辆数
                .setTotalReceiptMachineAgv(handleDiv(vo.getTotalReceiptOrderAmount(), Double.valueOf(vo.getPutInTotalMachine())))
                // 应收车均单量 = 应收订单数/投放车辆数
                .setTotalOrderPerMachine(handleDiv(Double.valueOf(vo.getTotalOrderCount()), Double.valueOf(vo.getPutInTotalMachine())))
                // 实收车均单量 = 实收订单数/投放车辆数
                .setTotalReceiptOrderPerMachine(handleDiv(Double.valueOf(vo.getTotalReceiptOrderCount()), Double.valueOf(vo.getPutInTotalMachine())))
                // 应收车均里程：（累计骑行总里程 米转公里：dataType=102 sumTotal）／应收订单数
                .setTotalDistancePerMachine(handleDiv(
                        getDoubleValue(record, AccountDayStatEnum.ACCUMULATED_MILEAGE, false) / 1000,
                        Double.valueOf(vo.getTotalOrderCount())
                ))
                // 实收车均里程：（累计骑行总里程：dataType=102）／实收订单数
                .setTotalReceiptDistancePerMachine(handleDiv(
                        getDoubleValue(record, AccountDayStatEnum.ACCUMULATED_MILEAGE, false) / 1000,
                        Double.valueOf(vo.getTotalReceiptOrderCount())
                ))
                // 应收车均时长：骑行总时长（分钟）dataType=133秒／应收订单数
                .setTotalTimePerMachine(handleDiv(
                        getDoubleValue(record, AccountDayStatEnum.MACHINE_RIDING_TIME, true) / 60,
                        Double.valueOf(vo.getTotalOrderCount())
                ))
                // 实收车均时长：骑行总时长（分钟）dataType=133秒／实收订单数
                .setTotalReceiptTimePerMachine(handleDiv(
                        getDoubleValue(record, AccountDayStatEnum.MACHINE_RIDING_TIME, true) / 60,
                        Double.valueOf(vo.getTotalReceiptOrderCount())
                ))
                // 用户数：（dataType=70累计用户数）
                .setTotalUserCount(getIntegerValue(record, AccountDayStatEnum.CUMULATIVE_NUMBER_OF_USERS, true))
                // 新增用户数：（dataType=43新增用户数）
                .setNewUserCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_NEW_USERS, true))
                // 骑行用户数 dataType=123
                .setRidingUserCount(getIntegerValue(record, AccountDayStatEnum.DAILY_RIDING_USER, true))
                // 3天未骑行用户数：dataType=140 3天有骑行用户数 sumTotal - cntTotal
                .setThreeDaysNoRidingUserCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_3_LAST_DAY_ORDER_USERS, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_3_LAST_DAY_ORDER_USERS, true))
                // 7天未骑行用户数：累计用户数－dataType=141 7天有骑行用户数 sumTotal - cntTotal
                .setSevenDaysNoRidingUserCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_7_LAST_DAY_ORDER_USERS, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_7_LAST_DAY_ORDER_USERS, true))
                // 15天未骑行用户数：累计用户数－dataType=142 15天有骑行用户数 sumTotal - cntTotal
                .setFifteenDaysNoRidingUserCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_15_LAST_DAY_ORDER_USERS, false) - getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_15_LAST_DAY_ORDER_USERS, true))
                // 用户7日留存率：7 dataType=143 7日留存率 存储的是4为小数的整数值 除以100转为百分比
                .setNewUserSevenDayRetentionRate(getDoubleValue(record, AccountDayStatEnum.RETENTION_RATE_OF_7_DAY_USERS, true) / 100)
                // 丢单次数 dataType=145
                .setLostOrderCount(getIntegerValue(record, AccountDayStatEnum.COUNT_OF_LOSE_ORDER, true))
                // 总换电次数：（dataType=67 换电次数）
                .setTotalPowerChangeCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_POWER_CHANGES, false))
                // 总挪车次数：(accountdaystat dataType=68 换电次数）
                .setTotalMoveCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_MOVES, false))
                // 总调度次数：（dataType=69 换电次数）
                .setTotalDispatchCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_DISPATCHES, false))
                // 总维修次数：(accountdaystat dataType=125 维修数)
                .setTotalRepairCount(getIntegerValue(record, AccountDayStatEnum.NUMBER_OF_REPAIR, false))
                // 换电有效率：dataType=144
                .setPowerChangeEfficiencyRate(getDoubleValue(record, AccountDayStatEnum.RATIO_NUMBER_OF_POWER_CHANGES, true))
                // 挪车完成率：(accountdaystat dataType=66 挪车完成率）
                .setMoveCompleteRate(getDoubleValue(record, AccountDayStatEnum.MOVING_COMPLETION_RATE, true))
                // 调度完成率：(accountdaystat dataType=65 调度完成率）
                .setDispatchEfficiencyRate(getDoubleValue(record, AccountDayStatEnum.EFFICIENCY_OF_DISPATCH, true))
                // 维修完成率；(accountdaystat  dataType=64 维修完成率)
                .setRepairCompleteRate(getDoubleValue(record, AccountDayStatEnum.REPAIR_COMPLETION_RATE, true))
                // 调度后12小时成单率 dataType=146 存储的是4为小数的整数值 除以100转为百分比
                .setDispatchAfter12HoursHasOrderRate(getDoubleValue(record, AccountDayStatEnum.RATIO_OF_DISPATCH_12_HOUR_HAS_ORDER, false) / 100)
        ;
        return vo;
    }

    private OperationReportListRespVo convertToOperationReportListRespVo(Map<String, Object> record) {
        if (record == null) {
            return OperationReportListRespVo.empty();
        }
        OperationReportListRespVo vo = new OperationReportListRespVo();
        // 设置数据
        convertToOperationReportRespVo(record, vo);
        vo
                // 数据日期
                .setDataDate(getIntegerValue(record, "dataDate"))
                // 区域id
                .setAccountId(getIntegerValue(record, "accountId"));
        return vo;
    }

    private int getIntegerValue(Map<String, Object> record, AccountDayStatEnum enumKey, boolean isCnt) {
        return getIntegerValue(record, isCnt ? enumKey.getCntFieldKey() : enumKey.getSumFieldKey());
    }

    private int getIntegerValue(Map<String, Object> record, String key) {
        Object value = record.get(key);
        return value != null ? Integer.parseInt(value.toString()) : 0;
    }

    private long getLongValue(Map<String, Object> record, AccountDayStatEnum enumKey, boolean isCnt) {
        Object value = record.get(isCnt ? enumKey.getCntFieldKey() : enumKey.getSumFieldKey());
        return value != null ? Long.parseLong(value.toString()) : 0L;
    }

    private double getDoubleValue(Map<String, Object> record, AccountDayStatEnum enumKey, boolean isCnt) {
        Object value = record.get(isCnt ? enumKey.getCntFieldKey() : enumKey.getSumFieldKey());
        return value != null ? Double.parseDouble(value.toString()) : 0.0D;
    }

    private Double handleRate(Integer validCount, Integer totalCount) {
        if (validCount == null || totalCount == null || validCount == 0 || totalCount == 0) {
            return BigDecimal.ZERO.doubleValue();
        }
        return BigDecimal.valueOf(validCount).divide(BigDecimal.valueOf(totalCount), 4, RoundingMode.HALF_UP).multiply(ONE_HUNDRED).doubleValue();
    }

    private Double handleDiv(Double validCount, Double totalCount) {
        if (validCount == null || totalCount == null || validCount == 0 || totalCount == 0) {
            return BigDecimal.ZERO.doubleValue();
        }
        return NumberUtil.div(validCount, totalCount, 2);
    }

    private Double fenToYuan(long fen) {
        return fen == 0 ? 0.0D : (double) fen / 100;
    }

    private final BigDecimal ONE_HUNDRED = new BigDecimal(100);
}
